package com.itheima.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.bean.Dish;
import com.itheima.bean.DishFlavor;
import com.itheima.dao.DishDao;
import com.itheima.dao.DishFlavorDao;
import com.itheima.dto.DishDto;
import com.itheima.exception.CustomException;
import com.itheima.service.DishService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

@Service
public class DishServiceImpl extends ServiceImpl<DishDao, Dish> implements DishService {

    @Autowired
    private DishFlavorDao dishFlavorDao;

    /*
       事务添加：
          原则：事务一般添加service层
          使用步骤：
              1.配置事务管理员						【可以省略 SpringBoot已经自动配置】
              2.在接口或接口方法打上@Transactional注解
              3.在启动类|配置类上打上@EnableTransactionMent注解
    */
    @Override
    public void saveWithFlavors(DishDto dishDto) {
        //0.检查菜品名称是否存在
        LambdaQueryWrapper<Dish> dishLambdaQueryWrapper = new LambdaQueryWrapper<>();
        dishLambdaQueryWrapper.eq(Dish::getName,dishDto.getName());
        int count = this.count(dishLambdaQueryWrapper);
        if(count>0){
            throw new CustomException("菜品名称【"+dishDto.getName()+"】已存在！");
        }

        //1.保存菜品基本信息到dish表中
        // 注意1：由于DishDao泛型时Dish 所以在新增时只会从Dishdto对象中拿Dish有的属性数据插入到数据库中 多余扩展的属性不要！！！
        // 注意2：MyBatisPlus自动完成了新增数据之后为对象的主键属性赋值  新增完之后 可以使用dishDto.getId()得到菜品的id
        this.save(dishDto);

        //2.保存菜品的口味信息到dish_flavor表中
        //获取新增菜品id
        Long dishId = dishDto.getId();
        //循环遍历 将新增菜品的每一条口味信息插入到菜品口味表中
        /*List<DishFlavor> flavors = dishDto.getFlavors();
        if(flavors!=null && flavors.size()>0){
            for (DishFlavor flavor : flavors) {
                flavor.setDishId(dishId);
                dishFlavorDao.insert(flavor);
            }
        }*/

        /*
            方法引用：
                使用场景：用于函数式接口或接口中只有一个抽象方法
                使用格式：()->{}
                省略规则：
                    1.如果参数只有一个 可以省略小括号
                    2.如果方法体中只有一句代码 可以省略大括号和return关键字
         */
        //使用Stream流循环遍历
        dishDto.getFlavors().stream().forEach(flavor -> {
            flavor.setDishId(dishId);
            dishFlavorDao.insert(flavor);
        });


    }

    @Override
    public DishDto getByIdWithFlavors(Long id) {
        //1.根据菜品id去dish表中查询菜品基本信息
        Dish dish = this.getById(id);

        //2.根据菜品id去dish_flavor表中查询菜品口味信息
        LambdaQueryWrapper<DishFlavor> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DishFlavor::getDishId,id);
        List<DishFlavor> dishFlavors = dishFlavorDao.selectList(wrapper);

        //3.将根据菜品id查询菜品基本信息和口味信息封装到DishDto对象中并返回
        DishDto dishDto = new DishDto();
        BeanUtils.copyProperties(dish,dishDto);
        dishDto.setFlavors(dishFlavors);

        return dishDto;
    }

    @Override
    public void updateWithFlavors(DishDto dishDto) {
        //1.验证修改后的菜品名称是否存在
        LambdaQueryWrapper<Dish> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Dish::getName, dishDto.getName());
        wrapper.ne(Dish::getId, dishDto.getId());   //不是自己
        int count = this.count(wrapper);
        if (count > 0) {
            throw new CustomException("菜品名称【" + dishDto.getName() + "】已经存在！");
        }

        //2.修改菜品的基本信息  操作dish表  由于DishDao操作的类泛型时Dish 所以关于DishDto对象中多余的属性会直接忽略
        this.updateById(dishDto);

        //3.修改菜品的口味信息  操作dish_flavor表
        Long dishId = dishDto.getId();  //菜品id

        //3.1：删除当前菜品原有的口味信息
        LambdaQueryWrapper<DishFlavor> dishFlavorLambdaQueryWrapper = new LambdaQueryWrapper<>();
        dishFlavorLambdaQueryWrapper.eq(DishFlavor::getDishId, dishId);
        dishFlavorDao.delete(dishFlavorLambdaQueryWrapper);

        //3.2：重新添加当前菜品的口味信息
        List<DishFlavor> flavors = dishDto.getFlavors();

        if (flavors != null && flavors.size() > 0) {
            for (DishFlavor flavor : flavors) {
                //a：重置口味id为null
                flavor.setId(null);
                //b：设置当前口味所属的菜品
                flavor.setDishId(dishId);
                //c：将口味信息插入到菜品口味表中
                dishFlavorDao.insert(flavor);
            }
        }
    }

    //停售启售|批量停售启售
    @Override
    public void changeStatusByIds(Long[] ids, Integer status) {
        // 获取当前id菜品
        List<Dish> dishes = this.listByIds(Arrays.asList(ids));
        for (Dish dish : dishes) {
            // 将status放入到当前菜品中
            dish.setStatus(status);
            // 传到数据库
            boolean flag = this.saveOrUpdate(dish);
            if (!flag) {
                throw new CustomException("修改" + dish.getName() + "失败");
            }
        }
    }

    //根据菜品id删除|批量删除
    @Override
    public boolean deleteByIds(Long[] ids) {
        //1.非空判断
        if (ids == null || ids.length == 0) {
            throw new CustomException("请选择要删除的菜品");
        }

        //2.判断是否关联启售中
        List<Dish> dishes = this.listByIds(Arrays.asList(ids));
        LambdaQueryWrapper<Dish> wrapper = new LambdaQueryWrapper<>();
        for (Dish dish : dishes) {
            if (dish.getStatus() == 1) {
                throw new CustomException("当前菜品[" + dish.getName() + "]正处于起售状态,不能删除");
            }
            //3.判断是否关联了套餐
            wrapper.eq(Dish::getCategoryId, dish.getId());
            int count = this.count(wrapper);
            if (count > 0) {
                throw new CustomException("该菜品已关联套餐");
            }
        }

        //4.根据id删除套餐表中setmeal_dish中套餐菜品基本信息数据
        LambdaQueryWrapper<DishFlavor> wrapper1 = new LambdaQueryWrapper<>();
        for (Long id : ids) {
            // 先根据id查询到口味表
            wrapper1.eq(DishFlavor::getDishId, id);
            // 判断该id是否在口味表中
            int count = dishFlavorDao.selectCount(wrapper1);
            if (count > 0) {
                // 若有则进行删除
                dishFlavorDao.delete(wrapper1);
            }
        }

        //5.执行删除操作
        boolean flag = this.removeByIds(Arrays.asList(ids));
        return flag;
    }
}
